Мы попытаемся найти зависимости продаж между регионами, по тем или иным признакам и попытаемся построить можель которая предскажет эти продажи.
Для начала импортируем данные и выполним первичный анализ.
import numpy as np
import matplotlib.pyplot as plt
import pandas as pd
%matplotlib inline
import seaborn as sns
sns.set_style('dark')
df = pd.read_csv('vgsales.csv')
df.head()
Датасет содержит список игр с продажами более 100 000 копий. Данные взяты с сайта vgchartz.com.
Rank - Ranking of overall sales
Name - название игры
Platform - платформа (т.е. PC,PS4, итд.)
Year - год выпуска
Genre - жанр
Publisher - издатель
NA_Sales - продажи в Северной Америке (в миллионах)
EU_Sales - продажи в Европе (в миллионах)
JP_Sales - продажи в Японии (в миллионах)
Other_Sales - продажи в остальных странах (в миллионах)
Global_Sales - суммарная продажа со всех стран
Посмотрим информацию о фичах.
df.info()
df.describe()
Данные довольно полные, это избавляет нас от надобности чистить их.
Посмотрим на доли продаж по годам и доли продаж по жанрам в раличных регионах
df[["NA_Sales", "EU_Sales", "JP_Sales", "Other_Sales","Global_Sales"]].sum()
sales_for_genres = []
for genre in df['Genre'].unique():
sales_for_genres += [df[df['Genre'] == genre]['Global_Sales'].sum()]
print(genre, sales_for_genres[-1])
df['Genre'].unique()
for ar in ["NA_Sales", "EU_Sales", "JP_Sales", "Other_Sales"]:
sales_for_genres_in_ar = []
for genre in df['Genre'].unique():
sales_for_genres_in_ar += [df[df['Genre'] == genre][ar].sum()]
plt.title(ar + ' and Global_sales')
plt.scatter(range(len(sales_for_genres_in_ar)), np.array(sales_for_genres_in_ar)/sum(np.array(sales_for_genres_in_ar)),c = 'y')
plt.scatter(range(len(sales_for_genres)), np.array(sales_for_genres)/sum(np.array(sales_for_genres)))
plt.show()
Отличия от общего тренда есть только в Японии. Здесь люди больше интересуются ролевыми играми и меньше шутерами.
sales_for_years = []
for year in np.sort(df['Year'].unique()):
sales_for_years += [df[df['Year'] == year]['Global_Sales'].sum()]
for ar in ["NA_Sales", "EU_Sales", "JP_Sales", "Other_Sales"]:
sales_for_years_in_ar = []
for year in np.sort(df['Year'].unique()):
sales_for_years_in_ar += [df[df['Year'] == year][ar].sum()]
plt.title(ar + ' and Global_sales')
plt.scatter(np.sort(df['Year'].unique()), np.array(sales_for_years_in_ar)/sum(np.array(sales_for_years_in_ar)), c = 'y')
plt.scatter(np.sort(df['Year'].unique()), np.array(sales_for_years)/sum(np.array(sales_for_years)))
plt.show()
Видим что на глобальном тренде есть два пика, приходящиеся на 2008 и 2013 года. В отличие от этого в Японии есть пик на играх 1996-го года выпуска. Кроме того глобаньй пик в Европе смещём вправо, а в других станах влево.
for col in ["Platform", "Genre", "Publisher"]:
for val in df[col].unique():
df[val] = (df[col] == val).astype(int)
corr = df.corr()[["NA_Sales","EU_Sales","JP_Sales","Other_Sales","Global_Sales"]]
corr.drop(['Rank','Platform', 'NA_Sales', 'EU_Sales', 'JP_Sales', 'Other_Sales', 'Global_Sales'], inplace=True)
gradient = np.linspace(-1, 1, 100)
gradient = np.vstack((gradient, gradient))
plt.xticks([])
plt.yticks([])
plt.imshow(gradient, aspect='auto', cmap=plt.get_cmap('bwr'))
plt.figure(figsize = (40,200))
plt.imshow(corr, cmap='bwr')
for i in range(60):
plt.annotate(corr.T.columns[i], (0,i))
Видим, что большая часть признаков имеет незначительную отрицательную корреляцию с целевыми переменными. Однако некоторые, признаки, как 'Nintendo' сильно коррелируют с продажами.
from sklearn.model_selection import train_test_split
data = df.dropna()
X = data.drop(["Rank", "Name", 'NA_Sales', 'EU_Sales', 'JP_Sales', 'Other_Sales', 'Global_Sales', "Genre", "Publisher"], axis = 1)
y = data.NA_Sales
train_data, test_data, train_labels, test_labels = train_test_split(X, np.array(y), test_size = 0.1,
random_state = 1)
from sklearn.ensemble import RandomForestRegressor
lin_classifier = RandomForestRegressor()
lin_classifier.fit(train_data, train_labels)
lin_predictions = lin_classifier.predict(test_data)
from sklearn import metrics
metrics.mean_squared_error(test_labels, lin_predictions)
Попробуем найти еще зависимости, может они покажут себя лучше.
Выведем количество игр относительно платформ
df['Platform'].value_counts()
Выведем количество игр относительно жанров
df['Genre'].value_counts()
Для улучшения анализа и визуализации избавимся от игр с издателями, которые опубликовали менее 50 игр и платформ с менее чем 90 играми. Издатели с менее чем 50 играми и платформы с меньше чем 90 играми будут переименованы в "Other".
for i in df['Publisher'].unique():
if df['Publisher'][df['Publisher'] == i].count() < 50:
df['Publisher'][df['Publisher'] == i] = 'Other'
for i in df['Platform'].unique():
if df['Platform'][df['Platform'] == i].count() < 90:
df['Platform'][df['Platform'] == i] = 'Other'
Посмотрим что поменялось
df['Publisher'].value_counts()
df['Platform'].value_counts()
Теперь после очистки построим графики
df['Publisher'].value_counts(sort=True).plot(kind='barh',figsize=(16,16))
df['Platform'].value_counts(sort=True).plot(kind='barh',figsize=(16,16))
Построим график по жанрам
sns.factorplot('Genre',data=df,kind='count',size=16)
Выведем количество игр имеющих более 1 миллиона копий, проданных в Свереной Америке и сгруппируем их по платформам
df.index.name = 'Index'
platform_name = []
platform_frequency = []
for i in df['Platform'].unique():
platform_name.append(i)
platform_frequency.append(df['Name'][df['NA_Sales'] > 1.0][df['Platform'] == i].count())
plat = pd.DataFrame()
plat["Name"] = platform_name
plat["Frequency"] = platform_frequency
plat
С помощью полученного выше датафрейма можем построить круговую диаграмму.
plat.plot(kind='pie',y='Frequency',labels=plat['Name'],legend=False,figsize=(16,16))
Посмотрим корелляцию между регионами
corr_1 = []
corr_2 = []
corr_res = []
sales_list = ['NA_Sales','EU_Sales','JP_Sales','Other_Sales','Global_Sales']
for i in sales_list:
for j in sales_list:
corr_1.append(i)
corr_2.append(j)
corr_res.append(df[i].corr(df[j]))
corr_data = pd.DataFrame(
{'Corr_1': corr_1,
'Corr_2': corr_2,
'Correlation': corr_res
})
corr_data = corr_data.pivot(values='Correlation',index='Corr_1',columns='Corr_2')
corr_data
plt.figure(figsize = (12,10))
sns.heatmap(corr_data)
Заметим высокую корреляцию продаж в Северной Америке и глобальные продажи.
sns.jointplot(x="NA_Sales", y="Global_Sales", data=df, kind='reg')
from sklearn.model_selection import train_test_split
X = df.iloc[:, 6].values
y = df.iloc[:, 10].values
X_train, X_test, y_train, y_test = train_test_split(X, y, test_size = 1/10, random_state = 0)
X_train = X_train.reshape((X_train.shape[0],1))
y_train = y_train.reshape((y_train.shape[0],1))
X_test = X_test.reshape((X_test.shape[0],1))
y_test = y_test.reshape((y_test.shape[0],1))
Импортируем регрессор из библиотеки sklearn. Обучимся на тестовой выборке.
from sklearn.linear_model import LinearRegression
regressor = LinearRegression()
regressor.fit(X_test, y_test)
y_pred_test = regressor.predict(X_test)
y_pred_train = regressor.predict(X_train)
plt.figure(figsize = (16,16))
plt.scatter(X_train, y_train, color='green')
plt.plot(X_train, y_pred_train, color='blue')
plt.title('Train set')
plt.xlabel('North America Sales')
plt.ylabel('Global Sales')
plt.show()
plt.figure(figsize = (16,16))
plt.scatter(X_test, y_test, color='green')
plt.plot(X_test, y_pred_test, color='blue')
plt.title('Test set')
plt.xlabel('North America Sales')
plt.ylabel('Global Sales')
plt.show()
print("Training score: {:.2f}".format(regressor.score(X_train,y_train)))
print("Test score: {:.2f}".format(regressor.score(X_test,y_test)))
Линейный регрессор показал даволько хороший результат. Попробуем что то по интереснее, к примеру дерево решений.
from sklearn.tree import DecisionTreeRegressor
X = X.reshape((X.shape[0],1))
y = y.reshape((y.shape[0],1))
Dregressor = DecisionTreeRegressor(random_state=0)
Dregressor.fit(X,y)
y_pred = Dregressor.predict(X)
X_grid = np.arange(min(X), max(X), 0.1)
X_grid = X_grid.reshape((len(X_grid), 1))
plt.figure(figsize = (16,16))
plt.scatter(X, y, color = 'green')
plt.plot(X_grid, Dregressor.predict(X_grid), color = 'blue')
plt.title('Decision Tree Regression')
plt.xlabel('North America Sales')
plt.ylabel('Global Sales')
plt.show()
from sklearn.externals.six import StringIO
from IPython.display import Image
from sklearn.tree import export_graphviz
import pydotplus
dot_data = StringIO()
export_graphviz(Dregressor, out_file=dot_data,
filled=True, rounded=True,
special_characters=True)
graph = pydotplus.graph_from_dot_data(dot_data.getvalue())
# дерево сохранено в файл dec_tree_games_max_depth.png
graph.write_png("dec_tree_games_max_depth.png")
Image(graph.create_png())
print("Decision tree score (max depth): {:.2f}".format(Dregressor.score(X,y)))
Дерево решений имеет лучший результат по сравнению с линейной регрессией. Однако оно получилось крайне широким, попробуем для лучшей визуализации уменьшить его глубину до 5 и посмотрим как изменится точность модели.
Dregressor = DecisionTreeRegressor(random_state=0, max_depth=5)
Dregressor.fit(X,y)
dot_data = StringIO()
export_graphviz(Dregressor, out_file=dot_data,
filled=True, rounded=True,
special_characters=True)
graph = pydotplus.graph_from_dot_data(dot_data.getvalue())
# дерево сохранено в файл dec_tree_games_depth_5.png
graph.write_png("dec_tree_games_depth_5.png")
Image(graph.create_png())
X_grid = np.arange(min(X), max(X), 0.1)
X_grid = X_grid.reshape((len(X_grid), 1))
plt.figure(figsize = (16,16))
plt.scatter(X, y, color = 'green')
plt.plot(X_grid, Dregressor.predict(X_grid), color = 'blue')
plt.title('Decision Tree Regression')
plt.xlabel('North America Sales')
plt.ylabel('Global Sales')
plt.show()
print("Decision tree score (depth = 5): {:.2f}".format(Dregressor.score(X,y)))
Как можно заметить точность уменьшилась на 0.03%. За то дерево сильно уменьшилось, что может помочь не переобучиться и ускорить работу модели.
from sklearn.ensemble import RandomForestRegressor
Rregressor = RandomForestRegressor(n_estimators=300, random_state=0)
Rregressor.fit(X,y)
y_pred = Rregressor.predict(X)
X_grid = np.arange(min(X), max(X), 0.01)
X_grid = X_grid.reshape((len(X_grid), 1))
plt.figure(figsize = (16,16))
plt.scatter(X, y, color = 'green')
plt.plot(X_grid, Rregressor.predict(X_grid), color = 'blue')
plt.title('(Random Forest Regression)')
plt.xlabel('North America Sales')
plt.ylabel('Global Sales')
plt.show()
print("Random Forest score: {:.2f}".format(Rregressor.score(X,y)))
Пока дерево решений все же показывает лучший результат.
Скорее всего метод покажет себя очень плохо, так как не очень подходит для наших целей.
from sklearn.svm import SVR
SVRregressor = SVR(kernel = 'rbf')
SVRregressor.fit(X,y)
Для нормальной работы алгоритма нужно произвести масштабирование фич.
from sklearn.preprocessing import StandardScaler
sc_X = StandardScaler()
sc_y = StandardScaler()
X = sc_X.fit_transform(X)
y = sc_y.fit_transform(y)
y_pred = sc_y.inverse_transform(SVRregressor.predict(sc_X.transform(X)))
X_grid = np.arange(min(X), max(X), 0.1)
X_grid = X_grid.reshape((len(X_grid), 1))
plt.figure(figsize = (16,16))
plt.scatter(X, y, color = 'green')
plt.plot(X_grid, SVRregressor.predict(X_grid), color = 'blue')
plt.title('(SVR)')
plt.xlabel('North America Sales')
plt.ylabel('Global Sales')
plt.show()
print("SVR score: {:.2f}".format(SVRregressor.score(X,y)))
Как и ожидалось, метод опорных векторов плохо себя показал.
Вывод: лучшей моделью для предсказания продаж оказалось дерево решений с неогранниченной глубиной, также неплохо себя показал случайный лес. Основываясь на продажах в Северной Америке мы можем с 95% вероятностью предсказать глобальные продажи.